package jmine.tec.script.impl.velocity;

import jmine.tec.utils.io.EncodingUtils;

import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.StringResourceLoader;
import org.apache.velocity.runtime.resource.util.StringResourceRepository;
import org.springframework.beans.factory.InitializingBean;

/**
 * Bean que contém a engine de velocity para execução de templates. Deve ser declarado no Spring e usado no executor de scripts velocity, um
 * por aplicação.
 * 
 * @author piercio
 */
public class VelocityEngineBean implements InitializingBean {

    public static final String RESOURCE_LOADER = "script";

    public static final String REPOSITORY_NAME = "scriptRepository";

    public static final String DESCRIPTION = "Velocity StringResource loader";

    private static final String RESOURCE_LOADER_CLASS = "script.resource.loader.class";

    private static final String RESOURCE_LOADER_DESCRIPTION = "script.resource.loader.description";

    private static final String RESOURCE_LOADER_REPOSITORY_NAME = "script.resource.loader.repository.name";

    private static final String RESOURCE_LOADER_REPOSITORY_STATIC = "script.resource.loader.repository.static";

    private final VelocityEngine engine = new VelocityEngine();

    private String inputCharset = EncodingUtils.UTF_CHARSET, outputCharset = EncodingUtils.UTF_CHARSET;
    
    /**
     * Inicializa o contexto do velocity com resource loader de string, usado para os scripts em banco.
     * 
     * @throws Exception caso não consiga inicializar o contexto.
     */
    public void afterPropertiesSet() throws Exception {
        this.engine.setProperty(RuntimeConstants.INPUT_ENCODING, this.getInputCharset());
        this.engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, this.getOutputCharset());
        this.engine.setProperty(Velocity.RESOURCE_LOADER, RESOURCE_LOADER);
        this.engine.setProperty(RESOURCE_LOADER_DESCRIPTION, DESCRIPTION);
        this.engine.setProperty(RESOURCE_LOADER_CLASS, StringResourceLoader.class.getCanonicalName());
        this.engine.setProperty(RESOURCE_LOADER_REPOSITORY_NAME, REPOSITORY_NAME);
        this.engine.setProperty(RESOURCE_LOADER_REPOSITORY_STATIC, "false");
        this.engine.init();
    }

    /**
     * Devolve um template velocity com o nome e corpo passados.
     * 
     * @param name o nome do template.
     * @param script o corpo do template.
     * @return o {@link Template}
     * @throws Exception caso ocorra algum erro na criação/recuperação do template.
     */
    public Template getTemplate(String name, String script) throws Exception {
        StringResourceRepository repo = (StringResourceRepository) this.engine.getApplicationAttribute(REPOSITORY_NAME);
        if (repo.getStringResource(name) == null) {
            repo.putStringResource(name, script, EncodingUtils.UTF_CHARSET);
        }
        return this.engine.getTemplate(name);
    }

    /**
     * @return the engine
     */
    public VelocityEngine getEngine() {
        return this.engine;
    }

    /**
     * @return the inputCharset
     */
    public String getInputCharset() {
        return inputCharset;
    }

    /**
     * @param inputCharset the inputCharset to set
     */
    public void setInputCharset(String inputCharset) {
        this.inputCharset = inputCharset;
    }

    /**
     * @return the outputCharset
     */
    public String getOutputCharset() {
        return outputCharset;
    }

    /**
     * @param outputCharset the outputCharset to set
     */
    public void setOutputCharset(String outputCharset) {
        this.outputCharset = outputCharset;
    }

}